package com.scholarship.modules.login.service;

import com.scholarship.common.config.BloomFilterHelper;
import com.scholarship.common.utils.BloomUtil;
import com.scholarship.modules.login.entity.User;
import com.scholarship.modules.login.mapper.LUserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * Redis测试业务
 * @Author Z.J.H
 * @create 2021/9/15 16:43
 */
@Service
public class RedisTestService {

    @Autowired
    private LUserMapper lUserMapper;

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    @Autowired
    private BloomFilterHelper bloomFilterHelper;

    @Autowired
    private BloomUtil bloomUtil;

    private Random random = new Random();

    /**
     * 解决缓存穿透
     * @return
     */
    public User getUser1(String userId) throws Exception {
        //从缓存中获取user信息
        User user = (User) redisTemplate.opsForValue().get(userId);

        if(user == null) {
            //如果缓存数据为空，从数据库中获取user信息
            user = lUserMapper.getUserByUserId(userId);

            if(user == null) {
                //如果数据库中数据为空，则存入一个空值，设置短时间内过期，防止缓存穿透
                redisTemplate.opsForValue().set(userId,null,3, TimeUnit.MINUTES);
            }else {
                //将数据写入缓存
                redisTemplate.opsForValue().set(userId,user);
            }
        }
//        List<User> userList = lUserMapper.listUser();
//        for(User user : userList) {
//            bloomUtil.addByBloomFilter(bloomFilterHelper,"bloomUser",user.getUserId());
//        }
        return user;
    }

    /**
     * 解决缓存穿透
     * @return
     */
    public User getUser4(String userId) {
        //先在布隆过滤器中查询userId是否存在
        Boolean flag = bloomUtil.includeByBloomFilter(bloomFilterHelper,"bloomUser",userId);
        if(flag == false) {
            return null;
        }

        //从缓存中获取user信息
        User user = (User) redisTemplate.opsForValue().get(userId);

        if(user == null) {
            //如果缓存数据为空，从数据库中获取user信息
            user = lUserMapper.getUserByUserId(userId);

            //将数据写入缓存
            redisTemplate.opsForValue().set(userId,user);
        }
        return user;
    }

    /**
     * 解决缓存雪崩
     * @return
     */
    public User getUser2(String userId) {
        //从缓存中获取user信息
        User user = (User) redisTemplate.opsForValue().get(userId);

        if(user == null) {
            //如果缓存数据为空，从数据库中获取user信息
            user = lUserMapper.getUserByUserId(userId);

            if(user == null) {
                redisTemplate.opsForValue().set(userId,null,3, TimeUnit.MINUTES);
            }else {
                //设置随机过期时间，将数据写入缓存，防止缓存雪崩
                long mins = random.nextInt(60) + 60;
                redisTemplate.opsForValue().set(userId, user, mins, TimeUnit.MINUTES);
            }
        }
        return user;
    }

    /**
     * 解决缓存击穿
     * @return
     */
    public User getUser3(String userId) {
        //从缓存中获取user信息
        User user = (User) redisTemplate.opsForValue().get(userId);

        //双重检测
        if(user == null) {
            //如果缓存数据为空，读取数据库的过程加锁
            synchronized(this) {
                //获取到锁后要再次判断缓存中是否存在数据
                //防止缓存击穿，大量请求访问数据库
                user = (User) redisTemplate.opsForValue().get(userId);

                if(user == null) {
                    //如果缓存数据还为空，从数据库中获取user信息
                    user = lUserMapper.getUserByUserId(userId);

                    if(user == null) {
                        redisTemplate.opsForValue().set(userId,null,3, TimeUnit.MINUTES);
                    }else {
                        long mins = random.nextInt(60) + 60;
                        redisTemplate.opsForValue().set(userId, user, mins, TimeUnit.MINUTES);
                    }
                }
            }
        }
        return user;
    }
}
